package com.seka.control.common.registrar;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import com.seka.control.common.annotation.SekaDiscoveryTask;
import com.seka.control.utils.BeanCacheUtil;
import com.seka.control.utils.SetUtil;

/**
 * seka 控制中心注册类
 * @author mw
 *
 */
@Component
public class SekaControlRegistrar implements ImportBeanDefinitionRegistrar,ResourceLoaderAware,EnvironmentAware
			{
	/**
	 * 日志
	 */
	private static final Logger LOG = LoggerFactory.getLogger(SekaControlRegistrar.class);

	/**
	 * 默认注册注解
	 */
	private static final String DEFAULT_ANNOTATION_PREFIX = "com.seka.control.common.annotation";
	
	/**
	 * 注册注解前缀配置key
	 */
	private static final String SEKA_REGISTART_ANNONTATION_PREFIX="seka.control.registrar.annotation.prefix";
	/**
	 * 类加载器
	 */
	private ResourceLoader resourceLoader;
	
	/**
	 * 运行环境
	 */
	private Environment environment;

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry);
		
		
		Map<String,Object> attrs = getClientAttrs(importingClassMetadata);
		Set<String> basePackages =  getBasePackages(attrs,importingClassMetadata.getClassName());
		Class<?>[] annos = getAnnotations(attrs);
		ClassPathScanningCandidateComponentProvider scan = getAnnotationScan(annos,environment,resourceLoader);
		for (String basePackage : basePackages) {
			Set<BeanDefinition> beans = scan.findCandidateComponents(basePackage);
			for (BeanDefinition bean : beans) {
				LOG.info("添加@SekaDiscoveryTask注解的类-->{}",bean.getBeanClassName());
				BeanCacheUtil.put(bean.getBeanClassName(), bean);
			}
		}
	}
	
	
	/**
	 * 获取扫描含指定注解的接口扫描器
	 * @param annos 需要扫描的注解
	 * @return
	 */
	private ClassPathScanningCandidateComponentProvider getAnnotationScan(Class<?>[] annos,Environment env,ResourceLoader loader) {
		ClassPathScanningCandidateComponentProvider scan = getInterfaceScan(env);
		scan.setResourceLoader(loader);
		for (Class<?> anno : annos) {
			if(anno.isAnnotation()) {
				scan.addIncludeFilter(new AnnotationTypeFilter((Class<? extends Annotation>)anno,true));
			}
		}
		return scan;
	}

	/**
	 * 获取接口扫描器
	 * @param env 环境
	 * @return 接口扫描器
	 */
	private ClassPathScanningCandidateComponentProvider getInterfaceScan(Environment env) {
		return new ClassPathScanningCandidateComponentProvider(false,env);
			 
	}

	/**
	 * 获取待扫描的注解类型
	 * @param attrs 注解属性集
	 * @return
	 */
	private Class<?>[] getAnnotations(Map<String, Object> attrs) {
		Class<?>[] annos = (Class<?>[])attrs.get("annotations");
		if(annos ==null || annos.length ==0) {
			return new Class<?>[] {SekaDiscoveryTask.class};
		}
		return annos;
	}




	/**
	 * 获取扫描基础包集
	 * @param attrs 属性集
	 * @param className 类名
	 * @return
	 */
	private Set<String> getBasePackages(Map<String, Object> attrs, String className) {
		Set<String> basePackages = new HashSet<>();
		String[] ps =(String[])attrs.get("value");
		SetUtil.arrToSet(ps,basePackages);
		ps = (String[])attrs.get("basePackages");
		SetUtil.arrToSet(ps,basePackages);
		if(basePackages.isEmpty()) {
			basePackages.add(ClassUtils.getPackageName(className));
		}
		return basePackages;
	}


	


	/**
	 * 获取服务配置属性
	 * @param metadata 注解元数据
	 * @return 服务配置属性
	 */
	private Map<String, Object> getClientAttrs(AnnotationMetadata metadata) {
		Map<String,Object> map = new HashMap<>();
		Set<String> names = metadata.getAnnotationTypes();
		String prefix = getImportAnnntationPrefix();
		String[] ps = prefix.split(",");
		for (String n : names) {
			for (String p : ps) {
				if(StringUtils.hasText(p) && n.startsWith(p.trim())){
					map.putAll(metadata.getAnnotationAttributes(n));
					break;
				}
			}
		}
		
		return map;
	}

	/**
	 * 获取导入注解前缀
	 * @return 导入注解前缀
	 */
	private String getImportAnnntationPrefix() {
		return environment.getProperty(SEKA_REGISTART_ANNONTATION_PREFIX, DEFAULT_ANNOTATION_PREFIX);
	}

	@Override
	public void setResourceLoader(ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
	}

	@Override
	public void setEnvironment(Environment environment) {
		this.environment = environment;
	}
 

}
